package com.haralabidis.jdeveloper.extension.subversionmonitor.addin;


import com.haralabidis.jdeveloper.extension.subversionmonitor.addin.editor.RevisionsEditor;
import com.haralabidis.jdeveloper.extension.subversionmonitor.addin.preferences.SubversionMonitorPreferences;
import com.haralabidis.jdeveloper.extension.subversionmonitor.util.svn.SubversionHelper;
import com.haralabidis.jdeveloper.extension.subversionmonitor.util.xml.XMLBuilder;

import java.awt.Component;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import java.net.URL;

import java.util.Iterator;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPopupMenu;
import javax.swing.Timer;

import oracle.bali.ewt.text.MultiLineLabel;
import oracle.bali.ewt.text.WordWrapper;

import oracle.ide.Ide;
import oracle.ide.config.Preferences;
import oracle.ide.editor.EditorUtil;
import oracle.ide.net.URLFactory;

import oracle.javatools.icons.OracleIcons;
import oracle.javatools.ui.balloon.Balloon;
import oracle.javatools.ui.balloon.BalloonConstraint;
import oracle.javatools.ui.balloon.BalloonManager;

import oracle.xml.parser.v2.XMLElement;


public class SubversionMonitor {

    private SubversionHelper subversionHelper = new SubversionHelper();
    private long lastRevision = -1;
    private String url = "";
    private String user = "";
    private String password = "";
    private boolean enabled = true;
    private int timeout = 60;

    private Timer timer =
        new Timer(SubversionMonitorPreferences.getInstance(Preferences.getPreferences()).getMonitorTimeout() *
                  1000, createTimerAction());

    private BalloonManager manager = null;
    private Balloon balloon;

    private JComponent statusIcon;
    private JCheckBox footer = null;
    private JPopupMenu optionsPopup = null;

    class SubversionMonitorClickThread implements Runnable {

        public void run() {
            if (subversionHelper.isAlive() &&
                subversionHelper.getLatestRevision() >
                lastRevision) { // re-create balloon if revision is changed
                lastRevision = subversionHelper.getLatestRevision();
                balloon =
                        createBalloon(!SubversionMonitorPreferences.getInstance(Preferences.getPreferences()).getMonitorDisabled());
            }

            // display the balloon
            manager.show(balloon, BalloonManager.TTL_OPTIONAL_USER_TASK);
        }
    }

    class SubversionMonitorInitThread implements Runnable {

        public void run() {
            subversionHelper.init(url, user, password);

            showBalloon(enabled); // create and show the ballon

            timer.setDelay(timeout * 1000);
            timer.stop();

            if (enabled && subversionHelper.isAlive()) {
                lastRevision =
                        subversionHelper.getLatestRevision(); // save the lastest revision

                timer.start(); // start the timer
            }
        }
    }

    public void init(String url, String user, String password, boolean enabled,
                     int timeout) {

        this.url = url; // save url
        this.user = user;
        this.password = password;
        this.enabled = enabled;
        this.timeout = timeout;

        SubversionMonitorInitThread thread = new SubversionMonitorInitThread();
        thread.run();
    }

    private void showBalloon(boolean enabled) {
        statusIcon = installStatusBarIcon(enabled);
        balloon = createBalloon(enabled);
        balloon.addActionListener(createBalloonAction());

        manager = BalloonManager.forTarget(statusIcon);
        manager.show(balloon, BalloonManager.TTL_OPTIONAL_USER_TASK);

        statusIcon.addMouseListener(createBalloonMouseListener());

        //        optionsPopup = new JPopupMenu();
        //        JMenuItem anItem = new JMenuItem("Preferences");
        //        optionsPopup.add(anItem);
    }

    private Icon icon() {
        return OracleIcons.getIcon(OracleIcons.TEAM);
    }

    private JComponent ideStatusTray() {
        return Ide.getStatusBar().getToolbar();
    }

    private void uninstallStatusBarIcon() {
        if (statusIcon != null) {
            ideStatusTray().remove(statusIcon);
            ideStatusTray().revalidate();
        }
    }

    private JComponent installStatusBarIcon(boolean enabled) {

        uninstallStatusBarIcon();

        JLabel icon = new JLabel();
        icon.setIcon(icon());
        //        icon.setToolTipText("Monitoring " +
        //                            SubversionMonitorPreferences.getInstance(Preferences.getPreferences()).getSubversionUrl() +
        //                            " is " + (enabled ? "enabled" : "disabled"));
        ideStatusTray().add(icon, 0);
        ideStatusTray().revalidate();

        return icon;
    }

    private Component createMultiLineLabel(String text) {
        MultiLineLabel label = new MultiLineLabel();
        label.setTextWrapper(WordWrapper.getTextWrapper());
        label.setPreferredColumns(80);
        label.setText(text);

        return label;
    }

    private Balloon createBalloon(boolean enabled) {

        JLabel header = new JLabel("Subversion Monitor");

        header.setIcon(icon());
        header.setFont(header.getFont().deriveFont(Font.BOLD));

        List<SubversionHelper.RevisionInfo> revisions =
            subversionHelper.getLogEntry(subversionHelper.getLatestRevision(),
                                         -1);

        Component headerText;
        Iterator revision = revisions.iterator();
        if (revision.hasNext()) {
            SubversionHelper.RevisionInfo revisionInfo =
                (SubversionHelper.RevisionInfo)revision.next();

            headerText =
                    createMultiLineLabel("Repository: " + subversionHelper.getRepositoryRoot() +
                                         "\nLatest revision: " +
                                         revisionInfo.getRevision() + "/" +
                                         revisionInfo.getAuthor() + "/" +
                                         revisionInfo.getDate() +
                                         "\nChanges: " +
                                         ((revisionInfo.getLog().length() >
                                           60) ?
                                          revisionInfo.getLog().substring(0,
                                                                          59) :
                                          revisionInfo.getLog()));
        } else {
            headerText =
                    createMultiLineLabel(this.url + "\nUnable to connect to repository!");
        }

        if (footer == null) { // create the footer only once
            footer = new JCheckBox("Disable monitoring");
            footer.setOpaque(false);
            footer.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent evt) {
                        if (footer.isSelected()) {
                            timer.stop();
                        } else {
                            timer.start();
                        }

                        SubversionMonitorPreferences.getInstance(Preferences.getPreferences()).setMonitorDisabled(footer.isSelected());

                        //                        statusIcon.setToolTipText("Monitoring " +
                        //                                                  SubversionMonitorPreferences.getInstance(Preferences.getPreferences()).getSubversionUrl() +
                        //                                                  " is " +
                        //                                                  (footer.isSelected() ?
                        //                                                   "disabled" : "enabled"));
                    }
                });
        }

        footer.setSelected(!enabled);

        Balloon balloon = new Balloon();
        balloon.add(header, BalloonConstraint.HEADER);
        balloon.add(headerText, BalloonConstraint.TEXT);
        balloon.add(footer, BalloonConstraint.FOOTER);

        return balloon;
    }

    protected ImageIcon createImageIcon(String path, String description) {
        java.net.URL imgURL = getClass().getResource(path);
        if (imgURL != null) {
            return new ImageIcon(imgURL, description);
        } else {
            System.err.println("Couldn't find file: " + path);
            return null;
        }
    }

    private ActionListener createTimerAction() {
        return new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {
                    // check for enabled
                    if (!footer.isSelected() &&
                        subversionHelper.getLatestRevision() > lastRevision) {
                        lastRevision = subversionHelper.getLatestRevision();
                        //balloon = createBalloon();
                        //manager.show(balloon,
                        //             BalloonManager.TTL_OPTIONAL_USER_TASK);
                        showBalloon(!SubversionMonitorPreferences.getInstance(Preferences.getPreferences()).getMonitorDisabled());
                    }

                } catch (Exception ex) {

                }
            }
        };
    }

    private Action createBalloonAction() {
        return new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                manager.hide(balloon);

                long startRevision =
                    (lastRevision - SubversionMonitorPreferences.getInstance(Preferences.getPreferences()).getMaxRevisionsToView()) + 1;
                List<SubversionHelper.RevisionInfo> revisions =
                    subversionHelper.getLogEntry(Math.max(startRevision, 0),
                                                 -1);

                // save to temporary file
                XMLBuilder builder =
                    new XMLBuilder("SubversionMonitor", "repository",
                                   subversionHelper.getRepositoryRoot());

                for (Iterator revision = revisions.iterator();
                     revision.hasNext(); ) {
                    SubversionHelper.RevisionInfo revisionInfo =
                        (SubversionHelper.RevisionInfo)revision.next();

                    XMLElement revisionElement =
                        builder.addElement(builder.getRootElement(),
                                           "revisionInfo", "revision",
                                           ((Long)revisionInfo.getRevision()).toString());

                    revisionElement.setAttribute("date",
                                                 revisionInfo.getDate().toString());
                    revisionElement.setAttribute("author",
                                                 revisionInfo.getAuthor());
                    revisionElement.setAttribute("log", revisionInfo.getLog());

                    List<SubversionHelper.RevisionInfo.ChangedPaths> changedPaths =
                        revisionInfo.getChangedPaths();
                    for (Iterator changedPath = changedPaths.iterator();
                         changedPath.hasNext(); ) {
                        SubversionHelper.RevisionInfo.ChangedPaths pathInfo =
                            (SubversionHelper.RevisionInfo.ChangedPaths)changedPath.next();

                        XMLElement pathElement =
                            builder.addElement(revisionElement, "changedPath",
                                               "type", pathInfo.getType());

                        pathElement.setAttribute("path", pathInfo.getPath());
                    }

                }

                builder.writeXMLToFile(Ide.getUserSettingsDirectory() +
                                       "/tmp/SubversionMonitor.submon");

                URL url =
                    URLFactory.newFileURL(Ide.getUserSettingsDirectory() +
                                          "/tmp/SubversionMonitor.submon");

                RevisionsEditor editor =
                    (RevisionsEditor)EditorUtil.openDefaultEditorInFrameExternal(url);
            }
        };
    }

    private MouseAdapter createBalloonMouseListener() {
        return new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                try {
                    if (MouseEvent.BUTTON1 == e.getButton()) {
                        new SubversionMonitorClickThread().run();
                    } else {
                        // optionsPopup.show(e.getComponent(), e.getX() + 10,
                        // e.getY() - 10);
                    }
                } catch (Exception ex) {

                }
            }
        };
    }

    private Action createPopupAction() {
        return new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                optionsPopup.show();
            }
        };
    }

}
